import random
from flask import Flask, render_template,redirect, request, jsonify
from werkzeug.utils import secure_filename
from flask_sqlalchemy import SQLAlchemy
import os
import cv2
import time
from myUtil import parse_result, isFakePlate
from datetime import timedelta
import pandas as pd
import numpy as np
from paddle_online_0911 import recognize_plate_online
# import darknet as dn
from hyperlpr import HyperLPR_PlateRecogntion as plateRecog  # 车牌识别库
# from hyperlpr import HyperLPR_plate_recognition as plateRecog
from keras.preprocessing.image import img_to_array
from keras.models import load_model
from datetime import datetime
#设置允许的文件格式
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'JPG', 'PNG', 'bmp'])
#vehicle_info_database = pd.read_csv('vehicle-database.csv')
cwd_path = os.getcwd()
cfg_path = cwd_path + "/cfg/yolov3-voc.cfg"
weights_path = cwd_path + "/cfg/yolov3-voc_final.weights"
data_path = cwd_path + "/cfg/voc.data"
VEHICLE_WIDTH = 28
VEHICLE_HEIGHT = 28
v_color_model_path = cwd_path + "/cfg/vehicle_color.hdf5" #
v_type_model_path = cwd_path + "/cfg/vehicle_type.hdf5"
global vehicle_info_database,net,meta
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
def prepare_service():
    global vehicle_info_database
    # 
    vehicle_info_database = pd.read_csv('vehicle-database.csv')
   
    return vehicle_info_database
# 生成只包含时间戳和后缀名的文件名
def generate_random_filename(filename):
    timestamp = int(time.time())  # 生成当前时间戳
    extension = os.path.splitext(filename)[1]  # 获取文件的后缀名（包括点，如 ".jpg"）
    return f"{timestamp}{extension}"

def create_filename_random(filename):
    timestamp = int(time.time()) #生成时间戳
    timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
    # filename_update = str(timestamp) + "_" + filename
    filename_update = f"{timestamp}_{filename}"
    print(f"filename_update {filename_update}")
    return filename_update
# 预测模块，输入图片，分析车牌信息和子品牌，跟车辆信息库对比查询，判定是否为嫌疑车辆
def predict(imgPath, vehicle_info_database):
    predictResult = "未识别"
    plateNo = "未识别"
    carBrandZh = "未识别"
    original_image = cv2.imread(imgPath)
    import subprocess
    import json
    # curl 命令
    curl_command = [
        'curl',
        '-X', 'POST',
        'http://localhost:8090/detect',
        # '-F', 'file=@/Users/jackiezheng/liushi/FindFakePlateVehicle-web/test.jpg'
         f'-F', f'file=@{imgPath}'  # 动态使用 imgPath 传递图片路径
    ]
    try:
        # 运行 curl 命令
        result = subprocess.run(curl_command, capture_output=True, text=True, check=True)
        # 打印状态码（curl 成功时总是返回 0）
        print(f"Command executed with return code: {result.returncode}")
        # 打印输出
        print("Response:")
        print(result.stdout)
        # 尝试解析 JSON 响应
        try:
            json_response = json.loads(result.stdout)
            print("Parsed JSON response:")
            print(json.dumps(json_response, ensure_ascii=False, indent=2))
            # predict_result_dict = [{
            #     "bbox": {"height": 499.37078857421875, "width": 547.970703125, "x": 677.2782592773438, "y": 427.50067138671875},
            #     "confidence": 0.9998480677604675, "label": "\u96ea\u4f5b\u5170"}]
            # 将返回的 JSON 数据重新格式化为需要的格式
            predict_result_dict = []
            for detection in json_response:
                x, y, width, height = detection['bbox']
                print(f"x1, y1, x2, y2{x, y, width, height}")
                formatted_bbox = {
                    'x': x,
                    'y': y,
                    'width': width,
                    'height': height
                }
                formatted_detection = {
                    'bbox': formatted_bbox,
                    'confidence': detection['confidence'],
                    'label': detection['label']
                }
                predict_result_dict.append(formatted_detection)
            print(f"predict_result_dict: {predict_result_dict}")
        except json.JSONDecodeError:
            print("Response is not valid JSON")
    except subprocess.CalledProcessError as e:
        print(f"Command failed with return code {e.returncode}")
        print("Error output:")
        print(e.stderr)
    except Exception as e:
        print(f"An error occurred: {e}")
    print(f"predict_result_dict: {predict_result_dict}")
    result_dict = parse_result(predict_result_dict) # 结果进行后处理
    for i in range(result_dict["b_box_num"]):
        x1_min = result_dict["detection_boxes"][i][0]
        y1_min = result_dict["detection_boxes"][i][1]
        
        x1_max = result_dict["detection_boxes"][i][2]
        y1_max = result_dict["detection_boxes"][i][3]
        carBrandZh = result_dict["detection_classes"][i] # 在线模型输出直接是中文字符串，而之前的离线模型是ascii编码的字符串

        print(f"carBranZh {carBrandZh}")
       # 截取汽车检测框的下面1/3部分，作为车牌检测的子区域。调用车牌识别，准确率和计算速度有保证
        left = x1_min
        top = int(y1_min + (y1_max - y1_min)*0.67)
        right = x1_max
        bottom = y1_max
        crop_image = original_image[top:bottom, left:right]

        # 使用随机文件名保存图片
        # crop_image_filename = generate_random_filename('crop_image.jpg')
        # gray_image_filename = generate_random_filename('gray_image.jpg')
        # roi_image_filename = generate_random_filename('roi_image.jpg')

        crop_image_filename = create_filename_random("crop_image.jpg")
        gray_image_filename = create_filename_random("gray_image.jpg")
        roi_image_filename = create_filename_random("roi_image.jpg")
        # 保存 crop_image
        # cv2.imwrite('crop_image.jpg', crop_image)
        cv2.imwrite(crop_image_filename, crop_image)
        grayImg = cv2.cvtColor(crop_image, cv2.COLOR_BGR2GRAY)
        # 保存 grayImg
        # cv2.imwrite('gray_image.jpg', grayImg)
        cv2.imwrite(gray_image_filename, grayImg)
        roi_img = cv2.resize(grayImg, (VEHICLE_WIDTH, VEHICLE_HEIGHT))
        roi_img = roi_img.astype("float")/255.0
        roi_img = img_to_array(roi_img)
        roi_img = np.expand_dims(roi_img, axis=0)

        # 保存 roi_img（转换为 8 位图像以便保存）
        # cv2.imwrite('roi_image.jpg', (roi_img[0] * 255).astype(np.uint8))
        cv2.imwrite(roi_image_filename, (roi_img[0] * 255).astype(np.uint8))

        (bus,car,minibus,truck) = v_type_model.predict(roi_img)[0]
        # cv2.imwrite('roi_img.jpg', roi_img)
        print(f"bus,car,minibus,truck{bus,car,minibus,truck}")
        v_type_result = {"bus":bus,"car":car,"minibus":minibus,"truck":truck}
        v_type_label = max(v_type_result,key=v_type_result.get)
        
        (black,blue,brown,green,red,silver,white,yellow ) = v_color_model.predict(roi_img)[0]
        v_color_result = {"black":black,"blue": blue, "brown":brown, "green":green, "red": red, "silver":silver,"white":white,"yellow":yellow}
        v_color_label = max(v_color_result, key=v_color_result.get)

        # 识别车牌号码信息
        # plateInfo = plateRecog(crop_image)
        plateNo = recognize_plate_online(imgPath)
        # if plateInfo:
        if plateNo:
            # 读取识别结果中的车牌号码
            # plateNo = plateInfo[0][0]
            inputCarInfo = [plateNo, carBrandZh]
            # print(inputCarInfo)
            isFake, true_car_brand = isFakePlate(inputCarInfo, vehicle_info_database)
            if isFake:
               predictResult = "这是一辆套牌车" 
            else:
               predictResult = "这是一辆正常车"    
        else:
            plateNo = "未识别"
            #carBrandZh = "未识别"
            predictResult = "车牌未识别，无法判定" 
            
    return plateNo, v_type_label, v_color_label, carBrandZh, predictResult
# ------------------------------------------------------------------------------------------------------------------------
app = Flask(__name__)
# 设置静态文件缓存过期时间
app.send_file_max_age_default = timedelta(seconds=1)
vehicle_info_database = prepare_service()
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)


class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(120), nullable=False)
# 在应用上下文环境中创建表
with app.app_context():
    db.create_all()
@app.route('/prepare')
def warm_up():
    vehicle_info_database = prepare_service()
    return redirect('/analyze')


@app.route('/', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        user = User.query.filter_by(username=username).first()
        if user and user.password == password:
            return redirect('/analyze')
        else:
            return render_template('login.html', error='用户名或密码错误')
    else:
        return render_template('login.html')


@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        new_username = request.form['new_username']
        new_password = request.form['new_password']
        new_user = User(username=new_username, password=new_password)
        db.session.add(new_user)
        db.session.commit()
        return redirect('/login')
    else:
        return render_template('register.html')

@app.route('/analyze', methods=['POST', 'GET'])  #` 添加路由
def analyze():
    if request.method == 'POST':
        f = request.files['file']
        if not (f and allowed_file(f.filename)):
            return jsonify({"error": 1001, "msg": "请检查上传的图片类型，仅限于png、PNG、jpg、JPG、bmp"})
        basepath = os.path.dirname(__file__)  # 当前文件所在路径
        relative_path = os.path.join('static/images', create_filename_random(f.filename))
        upload_path = os.path.join(basepath, relative_path)  # 拼接成绝对路径
        f.save(upload_path)
        read_path = os.path.join("./", relative_path)
        print(f"read path: {read_path}")
        img = cv2.imread(read_path)
        relative_path2 = os.path.join("static/images", create_filename_random("test.jpg"))
        save_path =  os.path.join(basepath, relative_path2)
        cv2.imwrite(save_path, img)
        read_path2 = os.path.join("./", relative_path2)
        # plate_no,v_type,v_color,car_brand, predict_result = predict(img_path, vehicle_info_database)
        plate_no, v_type, v_color, car_brand, predict_result = predict(read_path2, vehicle_info_database)
        context = ["车牌号："+plate_no,"车型："+ v_type,"车辆颜色："+v_color, "车辆品牌："+car_brand, "结论："+predict_result]
        return render_template('index.html', context = context, val1=time.time(), image_url=relative_path)
    return render_template('index.html')

 
if __name__ == '__main__':
    # app.debug = True
    app.run(host="0.0.0.0", port=5000, debug=True)
